using System;
using FireStarter.Base;
using FireStarter.Base.BusinessObjectMerger;
using Firestarter.DB.Schema.BO;
using Firestarter.DB.Schema.Logic;
using Firestarter.DB.Schema.Test.BO;
using Firestarter.DB.Schema.Test.BO.TestUtils;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using Habanero.Testability;
using NUnit.Framework;

namespace Firestarter.DB.Schema.Test.Logic
{
    [TestFixture]
    public class TestMergeDBPrimaryKeyColumn
    {
        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            ClassDef.ClassDefs.Clear();
            string xmlClassDefs = BOBroker.GetClassDefsXml();
            ClassDef.ClassDefs.Add(new XmlClassDefsLoader(xmlClassDefs, new DtdLoader()).LoadClassDefs());
            BORegistry.DataAccessor = new DataAccessorInMemory();

            MergeableBORegistry.Instance.Register<DBPrimaryKeyColumn, DBMergeDBPrimaryKeyColumn>();
        }

        [SetUp]
        public virtual void SetupTest()
        {
        }

        [TestCase("PrimaryKeyID", false)]
        [TestCase("ColumnID", false)]
        [TestCase("Approved", false)]
        [TestCase("PendingChangeType", false)]
        public void Test_MustMergeProp_ShouldBeSetForProp(string propName, bool expectedMustMergeProp)
        {
            //---------------Set up test pack-------------------
            DBMergeBO<DBPrimaryKeyColumn> merger = new DBMergeBO<DBPrimaryKeyColumn>();
            var dbForeignKey = new DBPrimaryKeyColumn();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            var boProp = dbForeignKey.Props[propName];
            var returnedMustMergeProp = merger.MustMergeProperty(boProp);
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedMustMergeProp, returnedMustMergeProp,
                            "Prop '" + propName + "' should be MustMerge = '" + expectedMustMergeProp + "'");
        }

        [TestCase("Column", false)]
        [TestCase("PrimaryKeyDB", false)]
        public void Test_MustMergeRelationship_ShouleBeSetForRelationships(string relationshipName,
                                                                           bool expectedMustMergeRel)
        {
            //---------------Set up test pack-------------------
            DBMergeBO<DBPrimaryKeyColumn> merger = new DBMergeBO<DBPrimaryKeyColumn>();
            var dbForeignKey = new DBPrimaryKeyColumn();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            var relationship = dbForeignKey.Relationships[relationshipName];
            var returnedMustMergeProp = merger.MustMergeRelationship(relationship);
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedMustMergeRel, returnedMustMergeProp,
                            "Relationship '" + relationship.RelationshipName + "' should be MustMerge = '" +
                            expectedMustMergeRel + "'");
        }

        [Test]
        public void Test_MatchPKColumn_WhenPropNameSame_ShouldMatch()
        {
            //---------------Set up test pack-------------------
            DBMergeDBPrimaryKeyColumn pkColumnMerger =
                (DBMergeDBPrimaryKeyColumn)MergeableBORegistry.Instance.Resolve<DBPrimaryKeyColumn>();
            var fromPKColumn = CreatePKColumnWithPK(RandomValueGen.GetRandomString());

            var toPKColumn = CreatePKColumnWithPK(fromPKColumn.ColumnName);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(toPKColumn.Column);
            Assert.IsNotNull(fromPKColumn.Column);
            Assert.AreEqual(toPKColumn.ColumnName, fromPKColumn.ColumnName);
            Assert.AreNotEqual(toPKColumn.ToString(), fromPKColumn.ToString());
            //---------------Execute Test ----------------------
            //pkColumnMerger.BusinessObject = fromPKColumn;
            Func<DBPrimaryKeyColumn, bool> matchFunction = pkColumnMerger.MatchBusinessObject(fromPKColumn);
            var matchBusinessObject = matchFunction(toPKColumn);
            //---------------Test Result -----------------------
            Assert.IsTrue(matchBusinessObject, "PK Columns should match");
        }


        [Test]
        public void Test_MergePKColumn_WhenColumnNull_ShouldDoNothing()
        {
            //---------------Set up test pack-------------------
            DBMergeDBPrimaryKeyColumn pkColumnMerger =
                (DBMergeDBPrimaryKeyColumn)MergeableBORegistry.Instance.Resolve<DBPrimaryKeyColumn>();

            var fromPKColumn = CreatePKColumnWithPK(null);
            fromPKColumn.Column = null;
            var toPKColumn = CreatePKColumnWithPK(null);
            toPKColumn.Column = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(fromPKColumn.Column);
            Assert.IsNotNull(fromPKColumn.PrimaryKeyDB);
            var fromTable = fromPKColumn.PrimaryKeyDB.Table;
            Assert.IsNotNull(fromTable);

            Assert.IsNull(toPKColumn.Column);
            Assert.IsNotNull(toPKColumn.PrimaryKeyDB);
            var toTable = toPKColumn.PrimaryKeyDB.Table;
            Assert.IsNotNull(toTable);
            //---------------Execute Test ----------------------
            pkColumnMerger.MergeBOFrom(fromPKColumn, toPKColumn);
            //---------------Test Result -----------------------
            Assert.Pass("If it got here all is OK");
        }

        [Test]
        public void Test_MergePKColumn_WhenPropNameSame_WhenToTableHasProp_ShouldSetColumnRelationshipOnPKColumn()
        {
            //---------------Set up test pack-------------------
            DBMergeDBPrimaryKeyColumn pkColumnMerger =
                (DBMergeDBPrimaryKeyColumn)MergeableBORegistry.Instance.Resolve<DBPrimaryKeyColumn>();

            var fromPKColumn = CreatePKColumnWithPK(RandomValueGen.GetRandomString());

            var toPKColumn = CreatePKColumnWithPK(fromPKColumn.ColumnName);
            toPKColumn.Column = null;
            //---------------Assert Precondition----------------
            Assert.IsNotNull(fromPKColumn.Column);
            Assert.IsNotNull(fromPKColumn.PrimaryKeyDB);
            var fromTable = fromPKColumn.PrimaryKeyDB.Table;
            Assert.IsNotNull(fromTable);
            Assert.IsTrue(fromTable.Columns.Contains(fromPKColumn.Column));

            Assert.IsNull(toPKColumn.Column);
            Assert.IsNotNull(toPKColumn.PrimaryKeyDB);
            var toTable = toPKColumn.PrimaryKeyDB.Table;
            Assert.IsNotNull(toTable);
            var expectedToColumn = toTable.Columns.Find(column => column.ColumnName == fromPKColumn.Column.ColumnName);
            Assert.IsNotNull(expectedToColumn);
            //---------------Execute Test ----------------------
            pkColumnMerger.MergeBOFrom(fromPKColumn, toPKColumn);
            //---------------Test Result -----------------------
            Assert.AreSame(expectedToColumn, toPKColumn.Column);
        }



        private static DBPrimaryKeyColumn CreatePKColumnWithPK(string parentColumnName)
        {
            var primaryKey = TestUtilsDBPrimaryKey.GetTestFactory()
                .CreateValidBusinessObject();
            DBColumn dbColumn = null;
            if (!string.IsNullOrEmpty(parentColumnName))
            {
                dbColumn = TestUtilsDBColumn.GetTestFactory()
                    .WithValue(column => column.ColumnName, parentColumnName)
                    .WithValue(column => column.Table, primaryKey.Table)
                    .CreateValidBusinessObject();
            }
            var pkColumn = TestUtilsDBPrimaryKeyColumn.GetTestFactory()
                .WithValue(property => property.PrimaryKeyDB, primaryKey)
                .WithValue(property => property.Column, dbColumn)
                .CreateValidBusinessObject();
            return pkColumn;
        }
    }

}